29. 农产品交易销售趋势与产品结构分析

⭐ 本章分析目标

本章围绕福建农产品交易数据,从两个维度展开深度分析:

  1. 销售趋势分析:时间规律、季节性、周期性
  2. 产品结构分析:市场格局、价格段、季节性差异

⭐ 数据准备:导入库与读取数据

Listing 1
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

⭐ 数据准备:产品分类映射

将具体产品名映射到大类,便于后续聚合分析:

Listing 2
# 产品分类映射字典
category_mapping = {
    '安溪铁观音': '茶叶',
    '武夷岩茶': '茶叶',
    '福州茉莉花': '茶叶',
    '古田银耳': '食用菌',
    '建宁莲子': '中药材',
    '琯溪蜜柚': '水果',
    '宁德大黄鱼': '水产品'
}

⭐ 销售趋势分析概述

销售趋势分析流程 展示销售趋势分析的四个核心步骤:每日趋势、月度汇总、季度品类、线性预测。 每日趋势 订单数 & 销售额 7日移动平均 月度汇总 柱状图展示 数据标签标注 季度品类 堆叠柱状图 品类结构对比 线性预测 LinearRegression 未来30天预测 销售趋势分析四步法 从日度粒度到季度粒度,逐步洞察销售规律

⭐ 每日销售趋势:核心思路

分析每日订单数与销售额的变化规律:

  • 按日期聚合groupby('下单日期') 统计每日订单数和销售额
  • 7日移动平均rolling(window=7) 平滑短期波动
  • 双子图展示:订单量趋势 + 销售额趋势

⭐ 每日销售趋势:关键代码解析

# 按日期聚合统计
daily_sales = data.groupby('下单日期').agg({
    'order_id': 'count',
    'sales_amount': 'sum'
}).reset_index()

# 计算7日移动平均线(平滑波动)
daily_sales['订单数_7日均值'] = daily_sales['订单数'].rolling(
    window=7, min_periods=1
).mean()
  • rolling(window=7):取最近7天的滑动窗口
  • min_periods=1:窗口内至少1个有效值即可计算

⭐ 月度销售数据:柱状图展示

将日度数据汇总到月度,便于观察整体变化:

# 提取年月标签
data['年月'] = pd.to_datetime(data['order_date']).dt.strftime('%Y-%m')

# 按月统计
monthly_sales = data.groupby('年月').agg({
    'order_id': 'count',
    'sales_amount': 'sum'
}).reset_index()
  • 使用 strftime('%Y-%m') 将日期转为”年-月”格式
  • 柱状图顶部添加数值标签,增强可读性

⭐ 季度品类销售额:堆叠柱状图

年-季度产品大类进行交叉统计:

# 提取年季标签
data['年季'] = (data['order_date'].dt.year.astype(str)
                + '-Q'
                + data['order_date'].dt.quarter.astype(str))

# 透视表便于绘图
quarterly_pivot = quarterly_category_sales.pivot(
    index='年季', columns='category', values='sales_amount'
).fillna(0)
  • pivot() 将长表转为宽表
  • stacked=True 绘制堆叠柱状图

⭐ 销售额预测:线性回归思路

使用 sklearn.linear_model.LinearRegression 进行简单趋势预测:

  1. 特征工程:将日期转为距起始日的天数
  2. 训练模型:分别拟合订单数和销售额
  3. 生成预测:预测未来30天数据
  4. 可视化:历史曲线 + 预测虚线 + 灰色预测区间

⭐ 销售额预测:关键代码

from sklearn.linear_model import LinearRegression

# 日期转数值特征
daily_sales['日期_数值'] = (
    pd.to_datetime(daily_sales['日期'])
    - pd.to_datetime(daily_sales['日期'].min())
).dt.days

# 训练模型并预测
model_sales = LinearRegression()
model_sales.fit(X, y_sales)
future_df['销售额预测'] = model_sales.predict(
    future_df[['日期_数值']]
)

⭐ 销售趋势分析完整代码

Listing 3
from datetime import datetime, timedelta
from matplotlib.dates import MonthLocator, DateFormatter
from sklearn.linear_model import LinearRegression

def sales_trend_analysis(orders):
    data['下单日期'] = pd.to_datetime(data['order_date']).dt.date
    daily_sales = data.groupby('下单日期').agg(
        {'order_id': 'count', 'sales_amount': 'sum'}
    ).reset_index()
    daily_sales.columns = ['日期', '订单数', '销售额']
    daily_sales['订单数_7日均值'] = daily_sales['订单数'].rolling(
        window=7, min_periods=1
    ).mean()
    daily_sales['销售额_7日均值'] = daily_sales['销售额'].rolling(
        window=7, min_periods=1
    ).mean()

    # 每日销售趋势双子图
    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(18, 14), sharex=True)
    ax1.plot(daily_sales['日期'], daily_sales['订单数'],
             'b-', alpha=0.3, label='每日订单数')
    ax1.plot(daily_sales['日期'], daily_sales['订单数_7日均值'],
             'r-', label='7日移动平均')
    ax1.set_title('每日订单量趋势')
    ax1.set_ylabel('订单数量')
    ax1.legend()
    ax1.grid(True)

    ax2.plot(daily_sales['日期'], daily_sales['销售额'],
             'g-', alpha=0.3, label='每日销售额')
    ax2.plot(daily_sales['日期'], daily_sales['销售额_7日均值'],
             'r-', label='7日移动平均')
    ax2.set_title('每日销售额趋势')
    ax2.set_xlabel('日期')
    ax2.set_ylabel('销售额(元)')
    ax2.legend()
    ax2.grid(True)
    ax2.xaxis.set_major_locator(MonthLocator())
    ax2.xaxis.set_major_formatter(DateFormatter('%Y-%m'))
    plt.tight_layout()
    plt.savefig('每日销售趋势.png')

    # 月度销售趋势
    data['年月'] = pd.to_datetime(data['order_date']).dt.strftime('%Y-%m')
    monthly_sales = data.groupby('年月').agg(
        {'order_id': 'count', 'sales_amount': 'sum'}
    ).reset_index()
    monthly_sales.columns = ['年月', '订单数', '销售额']

    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(16, 12))
    ax1.bar(monthly_sales['年月'], monthly_sales['订单数'], color='skyblue')
    ax1.set_title('月度订单数')
    ax1.set_ylabel('订单数量')
    plt.setp(ax1.xaxis.get_majorticklabels(), rotation=0)
    ax1.grid(axis='y')
    for i, v in enumerate(monthly_sales['订单数']):
        ax1.text(i, v + 10, str(v), ha='center', va='bottom', fontsize=10)

    ax2.bar(monthly_sales['年月'], monthly_sales['销售额'], color='lightgreen')
    ax2.set_title('月度销售额')
    ax2.set_xlabel('年月')
    ax2.set_ylabel('销售额(元)')
    plt.setp(ax2.xaxis.get_majorticklabels(), rotation=0)
    ax2.grid(axis='y')
    for i, v in enumerate(monthly_sales['销售额']):
        ax2.text(i, v + 1000, f'{v:.2f}', ha='center', va='bottom', fontsize=10)
    plt.tight_layout()
    plt.savefig('月度销售数据.png')

    # 季度商品大类销售额
    data['order_date'] = pd.to_datetime(data['order_date'])
    data['年季'] = (data['order_date'].dt.year.astype(str)
                    + '-Q' + data['order_date'].dt.quarter.astype(str))
    quarterly_category_sales = data.groupby(
        ['年季', 'category']
    )['sales_amount'].sum().reset_index()
    quarterly_pivot = quarterly_category_sales.pivot(
        index='年季', columns='category', values='sales_amount'
    ).fillna(0)

    ax = quarterly_pivot.plot(
        kind='bar', stacked=True, figsize=(16, 10), colormap='viridis'
    )
    ax.set_title('季度各品类销售额', fontsize=16)
    ax.set_xlabel('年-季度', fontsize=14)
    ax.set_ylabel('销售额(元)', fontsize=14)
    ax.legend(title='商品大类', bbox_to_anchor=(1.05, 1), loc='upper left')
    plt.xticks(rotation=0)
    ax.grid(axis='y')
    plt.tight_layout()
    plt.savefig('季度品类销售额.png')

    # 销售额线性预测
    daily_sales['日期_数值'] = (
        pd.to_datetime(daily_sales['日期'])
        - pd.to_datetime(daily_sales['日期'].min())
    ).dt.days
    X = daily_sales[['日期_数值']]
    y_orders = daily_sales['订单数']
    y_sales = daily_sales['销售额']

    model_orders = LinearRegression()
    model_sales = LinearRegression()
    model_orders.fit(X, y_orders)
    model_sales.fit(X, y_sales)

    last_date = pd.to_datetime(daily_sales['日期'].max())
    future_dates = [last_date + timedelta(days=i) for i in range(1, 31)]
    future_df = pd.DataFrame({'日期': future_dates})
    future_df['日期_数值'] = (
        pd.to_datetime(future_df['日期'])
        - pd.to_datetime(daily_sales['日期'].min())
    ).dt.days
    future_df['订单数预测'] = model_orders.predict(future_df[['日期_数值']])
    future_df['销售额预测'] = model_sales.predict(future_df[['日期_数值']])

    print('未来30天销售预测:')
    print(future_df.head(10))

    plt.figure(figsize=(18, 10))
    plt.plot(pd.to_datetime(daily_sales['日期']), daily_sales['销售额'],
             'b-', alpha=0.5, label='历史销售额')
    plt.plot(future_df['日期'], future_df['销售额预测'],
             'r--', label='销售额预测')
    plt.axvspan(last_date, future_df['日期'].max(), alpha=0.2, color='gray')
    plt.title('销售额趋势与预测')
    plt.xlabel('日期')
    plt.ylabel('销售额(元)')
    plt.legend()
    plt.grid(True)
    plt.tight_layout()
    plt.savefig('销售额预测.png')
    print('销售趋势分析完成')

⭐ 产品结构分析概述

产品结构分析五个维度 展示产品结构分析涵盖的五个核心维度:品类统计、子类Top3、价格段分析、树形图、季节性分析。 产品结构 分析 品类统计 大类销售额排名 子类 Top3 细分产品排名 价格段分析 订单/销售额占比 销售额树形图 季节性分析 热力图占比

⭐ 品类统计:按大类聚合销售数据

# 按商品大类统计
category_stats = data.groupby('category').agg({
    'order_id': 'count',
    'sales_amount': 'sum'
}).reset_index()
category_stats.columns = ['产品类型', '订单数', '销售额']

# 计算平均订单金额
category_stats['平均订单金额'] = (
    category_stats['销售额'] / category_stats['订单数']
)
category_stats = category_stats.sort_values('销售额', ascending=False)
  • agg() 同时计算多个聚合指标
  • 按销售额降序排列,快速定位核心品类

⭐ 商品定价分析:价格段划分

使用 pd.cut() 将连续价格离散化为价格段:

# 将价格划分为三个区间
data['价格段'] = pd.cut(
    data['price'],
    bins=[0, 100, 200, 500],
    labels=['0-100元', '100-200元', '200-500元']
)

# 按价格段统计订单数和销售额
price_range_stats = data.groupby('价格段').agg({
    'order_id': 'count',
    'sales_amount': 'sum'
}).reset_index()
  • bins 定义分割点,labels 定义区间标签
  • 分析不同价格段的订单占比与销售额占比

⭐ 树形图可视化:squarify 库

使用 squarify 绘制矩形树形图,直观展示各品类占比:

import squarify

category_sales['标签'] = (
    category_sales['产品类型'] + '\n'
    + category_sales['销售额'].apply(lambda x: f'{x:,.0f}元')
)

squarify.plot(
    sizes=category_sales['销售额'],
    label=category_sales['标签'],
    alpha=0.8,
    color=sns.color_palette('viridis', len(category_sales))
)
  • 矩形面积与销售额成正比
  • 一眼识别主力品类和长尾品类

⭐ 季节性销售分析:热力图

分析不同产品在四个季节的销售占比:

# 按季节和产品类型统计
seasonal_product = data.groupby(
    ['order_season', 'category']
)['sales_amount'].sum().reset_index()

# 透视 + 百分比计算
season_pivot = seasonal_product.pivot(
    index='category', columns='order_season',
    values='sales_amount'
)
season_pct = season_pivot.div(
    season_pivot.sum(axis=1), axis=0
) * 100
  • div(..., axis=0) 按行归一化
  • sns.heatmap() 以热力颜色直观展示差异

⭐ 平台任务解答代码

Listing 4
# 注:processed_data.csv数据文件本地没有,但平台已经内置;squarify包本地未安装,但平台已经内置
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import pandas as pd  # 导入Pandas数据分析库
import numpy as np  # 导入NumPy数值计算库
import matplotlib.pyplot as plt  # 导入Matplotlib绑图库
import seaborn as sns  # 导入Seaborn可视化库
import warnings  # 导入warnings模块用于控制警告输出
warnings.filterwarnings('ignore')  # 忽略警告
plt.rcParams['font.sans-serif'] = ['SimHei']  # 中文显示
plt.rcParams['axes.unicode_minus'] = False  # 负号显示
data = pd.read_csv('processed_data.csv')  # 读取数据

# 产品分类映射
category_mapping = {'安溪铁观音':'茶叶','武夷岩茶':'茶叶','福州茉莉花':'茶叶','古田银耳':'食用菌','建宁莲子':'中药材','琯溪蜜柚':'水果','宁德大黄鱼':'水产品'}
data['category'] = data['product_name'].map(category_mapping).fillna(data['category'])  # 更新产品分类
print(data.head())  # 查看数据

# 产品分析
import squarify  # 导入树形图库
# 创建季节特征(复用之前的季节映射)
seasons = {1: '冬季', 2: '冬季', 3: '春季', 4: '春季', 5: '春季', 6: '夏季', 7: '夏季', 8: '夏季', 9: '秋季', 10: '秋季', 11: '秋季', 12: '冬季'}
data['下单月份'] = pd.to_datetime(data['order_date']).dt.month  # 提取月份
data['order_season'] = data['下单月份'].map(seasons)  # 映射季节

def product_analysis(orders):  # 产品分析函数
    # 按商品大类统计销售数据
    category_stats = data.groupby('category').agg({'order_id':'count','sales_amount':'sum'}).reset_index()  #【要求1】
    category_stats.columns = ['产品类型', '订单数', '销售额']  # 重命名列
    category_stats['平均订单金额'] = category_stats['销售额'] / category_stats['订单数']  # 计算平均订单金额
    category_stats = category_stats.sort_values('销售额', ascending=False)  # 按销售额排序
    
    # 显示商品大类统计
    print("产品类型统计:")
        print(category_stats)  # 输出统计量数据
    
    # 可视化商品大类销售额
    plt.figure(figsize=(14, 8))
    sns.barplot(x='产品类型', y='销售额', data=category_stats, palette='viridis')  # 绑制分类柱状图
    plt.title('各商品大类销售额')  # 设置图表标题
    plt.xlabel('产品类型')  # 设置X轴标签
    plt.ylabel('销售额(元)')  # 设置Y轴标签
    plt.grid(axis='y')  # 显示网格线
    plt.tight_layout()  # 自动调整布局防止重叠
    plt.savefig("商品大类销售额.png")  # 保存图表
    
    # 按商品子类统计销售数据
    subcategory_stats = data.groupby(['category', 'product_name']).agg({'order_id':'count','sales_amount':'sum'}).reset_index()  
    subcategory_stats.columns = ['产品类型', '产品子类', '订单数', '销售额']  # 重命名列
    subcategory_stats['平均订单金额'] = subcategory_stats['销售额'] / subcategory_stats['订单数']  # 计算平均订单金额
    subcategory_stats = subcategory_stats.sort_values('销售额', ascending=False)  # 按销售额排序
    
    # 显示Top3商品子类
    print("产品子类统计:")
    print(subcategory_stats.head(3))  # 输出前几行数据
    
    # 可视化Top3商品子类销售额
    top_subcategories = subcategory_stats.head(3)
    plt.figure(figsize=(16, 10))  # 创建图形画布
    sns.barplot(x='销售额', y='产品子类', hue='产品类型', data=top_subcategories, palette='viridis')  # 绑制分类柱状图
    plt.title('各产品子类销售额Top 3')  # 设置图表标题
    plt.xlabel('销售额(元)')  # 设置X轴标签
    plt.ylabel('产品子类')  # 设置Y轴标签
    plt.grid(axis='x')  # 显示网格线
    plt.tight_layout()  # 自动调整布局防止重叠
    plt.savefig("Top3子类销售额.png")  # 保存图表
    
    # 商品定价分析
    data['价格段'] = pd.cut(data['price'], bins=[0, 100, 200, 500], labels=['0-100元', '100-200元', '200-500元'])  #【要求2】
    
    # 按价格段统计销售数据
    price_range_stats = data.groupby('价格段').agg({'order_id':'count','sales_amount':'sum'}).reset_index()
    price_range_stats.columns = ['价格段', '订单数', '销售额']  # 重命名列
    price_range_stats['订单占比'] = price_range_stats['订单数'] / price_range_stats['订单数'].sum() * 100  # 计算订单占比
    price_range_stats['销售额占比'] = price_range_stats['销售额'] / price_range_stats['销售额'].sum() * 100  # 计算销售额占比
    # 显示价格段统计
    print("价格段统计:")
        print(price_range_stats)  # 输出价格数据
    
    # 可视化价格段销售情况
    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(16, 14))
    
    # 订单数占比柱状图
    sns.barplot(x='价格段', y='订单占比', data=price_range_stats, palette='Blues_d', ax=ax1)
    ax1.set_title('各价格段订单数占比')  # 设置图表标题
    ax1.set_xlabel('价格段')  # 设置X轴标签
    ax1.set_ylabel('订单数占比(%)')  # 设置Y轴标签
    ax1.grid(axis='y')  # 设置网格线
    
    # 销售额占比柱状图
    sns.barplot(x='价格段', y='销售额占比', data=price_range_stats, palette='Reds_d', ax=ax2)
    ax2.set_title('各价格段销售额占比')  # 设置图表标题
    ax2.set_xlabel('价格段')  # 设置X轴标签
    ax2.set_ylabel('销售额占比(%)')  # 设置Y轴标签
    ax2.grid(axis='y')  # 设置网格线
    plt.tight_layout()  # 自动调整布局防止重叠
    plt.savefig("价格段销售占比.png")  # 保存图表
    
    # 商品销售分布树形图
    plt.figure(figsize=(16, 12))
    category_sales = category_stats[['产品类型', '销售额']].copy()  # 创建数据副本
    category_sales['标签'] = category_sales['产品类型'] + '\n' + category_sales['销售额'].apply(lambda x: f'{x:,.0f}元')  # 生成标签
    squarify.plot(sizes=category_sales['销售额'], label=category_sales['标签'], alpha=0.8, color=sns.color_palette("viridis", len(category_sales)))  # 绘制树形图
        plt.axis('off')  # 隐藏坐标轴
    plt.title('各产品类型销售额树形图', fontsize=18)  # 设置图表标题
    plt.tight_layout()  # 自动调整布局防止重叠
    plt.savefig("产品销售额树形图.png")  # 保存图表
    
    # 商品季节性分析
    seasonal_product = data.groupby(['order_season', 'category'])['sales_amount'].sum().reset_index()  # 按季节和产品类型统计销售额
    season_pivot = seasonal_product.pivot(index='category', columns='order_season', values='sales_amount')  # 【要求3】
    season_pct = season_pivot.div(season_pivot.sum(axis=1), axis=0) * 100  # 计算各季节占比
    
    # 显示季节性销售占比
    print("季节商品销售占比(%):")
        print(season_pct)  # 输出百分比数据
    
    # 可视化季节性销售占比
    plt.figure(figsize=(14, 10))
    sns.heatmap(season_pct, annot=True, fmt='.1f', cmap='YlGnBu')  # 绘制热力图
    plt.title('各产品类型在不同季节的销售占比(%)')  # 设置图表标题
    plt.xlabel('季节')  # 设置X轴标签
    plt.ylabel('产品类型')  # 设置Y轴标签
    plt.tight_layout()  # 自动调整布局防止重叠
    plt.savefig("产品季节销售占比.png")  # 保存图表
    print("产品分析完成")  # 输出产品分析完成

# 进行产品分析
product_analysis(data)

⭐ 品类销售额柱状图(独立实现)

Listing 5
# 该代码块依赖平台数据,此处展示分析逻辑

# 按品类统计销售数据
# category_sales = data.groupby('category')['sales_amount'].sum()
#     .sort_values(ascending=False)

# 创建柱状图并添加万元单位的数值标签
# for bar in bars:
#     height = bar.get_height()
#     plt.text(
#         bar.get_x() + bar.get_width() / 2.,
#         height,
#         f'{height/10000:.1f}万',
#         ha='center', va='bottom', fontsize=11
#     )

⭐ 分析结论

分析维度 核心发现
销售趋势 存在明显的周期性和季节性波动
核心品类 茶叶是主要销售品类,贡献最大销售额
移动平均 7日均线平滑短期波动,更易观察长期趋势
价格结构 不同价格段的订单量和销售额占比差异显著
季节效应 各品类在不同季节表现各异,需差异化运营

⭐ 业务建议

  • 库存管理:根据季节性规律提前备货,避免旺季缺货
  • 营销策略:针对核心品类(茶叶)加大推广投入
  • 价格优化:关注高销售额价格段,优化定价策略
  • 产品组合:根据季节性差异调整品类组合推荐
  • 趋势预测:利用线性回归模型辅助销售决策